﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Red.Core;
using Red.Launcher.Utilities;
using Sql = Red.Launcher.ViewModels.Workspaces.Database.Sql;
using P4 = Red.Core.Perforce;

namespace Red.Launcher.ViewModels.Workspaces
{
    public abstract class Workspace : ViewModel
    {
        #region Private Data

        private string _busyMessage = "Undefined";
        private bool _isSyncing;
        private bool _isActive;

        #endregion Private Data

        #region Abstract Properties

        public abstract string Uid { get; }
        public abstract bool IsInstalled { get; }
        public abstract string IsInstalledDescription { get; }
        public abstract string PerforceName { get; }
        public abstract string PerforceNameShort { get; }
        public virtual string PerforceStreamId => (!IsInstalled)? "Not Installed" : FetchPerforceStreamId() ?? "Unable to fetch Stream id";
        public virtual bool IsUpToDate => true;

        #endregion Abstract Properties

        #region Public Properties

        public bool IsBusy
        {
            get { return _isSyncing; }
            set
            {
                if ( _isSyncing != value )
                {
                    _isSyncing = value;
                    OnPropertyChanged();
                }
            }
        }
        public string BusyMessage
        {
            get { return _busyMessage; }
            set
            {
                if ( _busyMessage != value )
                {
                    _busyMessage = value;
                    OnPropertyChanged();
                }
            }
        }

        public bool IsActive
        {
            get { return _isActive; }
            set
            {
                if ( _isActive != value )
                {
                    _isActive = value;

                    OnActive?.Invoke( this, _isActive );

                    OnPropertyChanged();
                }
            }
        }

        public string DisplayName => WorkspaceInfo.Name;
        public Dictionary<string, string> Parameters { get; private set; } = new Dictionary<string, string>();
        public Database.Record WorkspaceInfo { get; set; }
        public Database.P4Credential Credentials { get; set; }

        #endregion Public Properties

        #region Abstract Methods

        protected Sql.ISql FetchParametersGenerateSql()
        {
            Sql.Select query = new Sql.Select();
            query.Sources.Add( Sql.Select.CreateTable( Database.ClientParameter.METADATA.Table ) );
            query.AddColumn( "parameter" );
            query.AddColumn( "value" );
            query.Conditions.AddLiteral( WorkspaceInfo.Metadata.ForeignKey, WorkspaceInfo.Id );

            return query;
        }

        public virtual Task<bool> CreateInPerforce( string location ) { return Task.FromResult( false ); }
        public virtual Task<bool> UpdateInPerforce() { return Task.FromResult( false ); }

        #endregion Abstract Methods

        #region Public Methods

        public async Task FetchParameters()
        {
            Sql.ISql query = FetchParametersGenerateSql();

            await DatabaseHelper.FetchAsync( query.Sql, Settings.DatabaseConnectionString, FetchParameterObject );
        }

        #endregion Public Methods

        #region Private Methods

        private string FetchPerforceStreamId()
        {
            if ( Credentials == null )
                return null;

            P4.Mediator mediator = new P4.Mediator( Settings.PerforceServer, Credentials.Name, null );

            return mediator.GetWorkspaceStream( PerforceName );
        }

        private void FetchParameterObject( Dictionary<string, object> row )
        {
            object param = row[ "parameter" ];
            object value = row[ "value" ];

            if ( !param.Equals( DBNull.Value ) && !value.Equals( DBNull.Value ) )
            {
                Parameters.Add( (string)param, (string)value );
            }
        }

        #endregion Private Methods

        #region Events

        public delegate void Active( Workspace workspace, bool isActive );
        public event Active OnActive;

        #endregion Events
    }

    public class LocalWorkspace : Workspace
    {
        #region Implemented Properties

        public override string Uid => $"LocalWorkspace.{WorkspaceInfo.Id}";
        public override bool IsInstalled => true;
        public override string IsInstalledDescription => "Installed";
        public override string PerforceName => ( (Database.P4ClientWorkspace)WorkspaceInfo ).PerforceName;
        public override string PerforceNameShort => PerforceName;

        #endregion Implemented Properties
    }
}
